// 12.1 动态内存与智能指针
/**
 * 在C++中，动态内存的管理是通过一对运算符来完成的：
 * 1. new，在动态内存中为对象分配空间并返回一个指向该对象的指针，我们可以选择对对象进行初始化；
 * 2. delete，接受一个动态对象的指针，销毁该对象，并释放与之关联的内存。
 * 新标准库提供的这两种智能指针的区别在于管理底层指针的方式：
 * 1. shared_ptr允许多个指针指向同一个对象；
 * 2. unique_ptr则“独占”所指向的对象。
 * 标准库还定义了一个名为weak_ptr的伴随类，它是一种弱引用，指向shared_ptr所管理的对象。这三种类型都定义在memory头文件中。
 */

#include <iterator>
#include <vector>
#include <list>
#include <deque>
#include <forward_list>
#include <string>
#include <array>
#include <stack>
#include <queue>
#include <algorithm>
#include <numeric>
using std::swap;
using std::vector, std::list, std::deque, std::forward_list, std::string, std::array, std::stack, std::queue;
#include "../Chapter07/Sales_data.h"
#include <iostream>
using std::begin, std::cbegin, std::end, std::cend, std::find, std::accumulate, std::equal, std::fill, std::fill_n, std::back_inserter;
using std::cin, std::cout, std::endl;
using std::copy, std::replace, std::replace_copy;
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <memory>
#include <new>
using namespace std;

int main()
{
    // 12.1.4 智能指针和异常
    // 如果使用智能指针，即使程序块过早结束，智能指针类也能确保在内存不再需要时将其释放，：[插图]
    { // 新程序块
        shared_ptr<int> sp(new int(18)); // 分配一个新对象
        // 假设这里抛出一个异常
    } // 程序块结束，shared_ptr自动释放内存
    // 与之相对的，当发生异常时，我们直接管理的内存是不会自动释放的。
    {
        int *ip = new int(18);
        // 假设这里抛出一个异常
        delete ip; // 内存不会被释放
    }

    // 智能指针和哑类
    // 包括所有标准库类在内的很多C++类都定义了析构函数（参见12.1.1节，第402页），负责清理对象使用的资源。但是，不是所有的类都是这样良好定义的。
    // 那些分配了资源，而又没有定义析构函数来释放这些资源的类，可能会遇到与使用动态内存相同的错误——程序员非常容易忘记释放资源。

    // 使用我们自己的释放操作
    // 默认情况下，shared_ptr假定它们指向的是动态内存。因此，当一个shared_ptr被销毁时，它默认地对它管理的指针进行delete操作。
    // 当我们创建一个shared_ptr时，可以传递一个（可选的）指向删除器函数的参数（参见6.7节，第221页）：[插图]

    // 注意：智能指针陷阱
    // 智能指针可以提供对动态分配的内存安全而又方便的管理，但这建立在正确使用的前提下。为了正确使用智能指针，我们必须坚持一些基本规范：
    // 1. · 不使用相同的内置指针值初始化（或reset）多个智能指针。
    // 2. · 不delete get（）返回的指针。
    // 3. · 不使用get（）初始化或reset另一个智能指针。
    // 4. · 如果你使用get（）返回的指针，记住当最后一个对应的智能指针销毁后，你的指针就变为无效了。
    // 5. · 如果你使用智能指针管理的资源不是new分配的内存，记住传递给它一个删除器（参见12.1.4节，第415页和12.1.5节，第419页）。

    return 0;
}